package com.test.configure;

import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 *
 在Spring下我们要使用线程池其实非常的简单，
 只需在要异步调用的方法上加上@Async注解即可。以后调用该方法时，
 Spring就会自动使用默认的线程池，创建一个线程异步调用该方法。但这样做会不会有什么问题呢？
 有没有我们需要优化的点呢？答案是肯定的！
 Spring默认使用的Executor bean，和我们使用JDK中的Executors创建的线程池一样，
 都存在着阻塞队列的长度过长，可能会堆积大量的请求，从而导致OOM的问题。
 所以为了规避资源耗尽，我们一般会自己配置Executor bean
 */
//多线程配置
@Configuration
public class AsyncConfiguration {
    //手动配置bean
    @Bean("executorOne")
    public ThreadPoolTaskExecutor getExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数：线程池创建时候初始化的线程数
        executor.setCorePoolSize(2);
        // 最大线程数：线程池最大的线程数，只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(6);
        // 缓冲队列：用来缓冲执行任务的队列
        executor.setQueueCapacity(3);
        // 允许线程的空闲(存活)时间秒：当超过了核心线程之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        // 线程池名的前缀：设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("one-executor-do-");
        // 缓冲队列满了之后的拒绝策略：由调用线程处理（一般是主线程）
        /**
         * AbortPolicy：丢弃任务，抛出运行时异常
         * CallerRunsPolicy：由提交任务的线程来执行任务
         * DiscardPolicy：丢弃这个任务，但是不抛异常
         * DiscardOldestPolicy：从队列中剔除最先进入队列的任务，然后再次提交任务
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }
}
